﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Reflection;
using System.IO;
using GameEngine;
using Daphne.Presenters;
using Daphne.Forms;
using System.Windows.Controls.Ribbon;

using ComputerEngine;
using System.ComponentModel;
using MHWrap = Daphne.MoveHelperWrapper;


namespace Daphne
{
    /// <summary>
    /// Game logic routines of MainWindow
    /// </summary>
    public partial class MainWindow
    {
        private bool _bRunningComputerAdvice = false;

        // engine settings
        private int _iEngineLevel = 1;
        List<EngineSettings> _lstSettings = new List<EngineSettings>()
        {
            new EngineSettings() { SearchType = eSearchType.NegaMax , MaxSeconds = 0, MaxDepth = 4, 
                                  UseCache = false,  UseEndGameDB = false, CacheSizeMB = 256, UseHistoryHeuristics = false, 
                                  UseKillerMoves = false, UsePositionStrategy = false},
            new EngineSettings() { SearchType = eSearchType.NegaMax, MaxSeconds = 0, MaxDepth = 6, UseCache = false,  
                                    UseEndGameDB = false, CacheSizeMB = 256, UseHistoryHeuristics = false, 
                                  UseKillerMoves = false, UsePositionStrategy = false},
            new EngineSettings() { SearchType = eSearchType.AlphaBeta , MaxSeconds = 1, MaxDepth = 0, UseCache = false,  
                                    UseEndGameDB = true, CacheSizeMB = 256, UseHistoryHeuristics = false, 
                                  UseKillerMoves = true, UsePositionStrategy = false},
            new EngineSettings() { SearchType = eSearchType.AlphaBeta , MaxSeconds = 2, MaxDepth = 0, UseCache = true,  
                                    UseEndGameDB = true, CacheSizeMB = 256, UseHistoryHeuristics = false, 
                                  UseKillerMoves = true, UsePositionStrategy = true},
            new EngineSettings() { SearchType = eSearchType.AlphaBeta , MaxSeconds = 4, MaxDepth = 0, UseCache = true,  
                                    UseEndGameDB = true, CacheSizeMB = 256, UseHistoryHeuristics = false, 
                                  UseKillerMoves = true, UsePositionStrategy = true}
        };





        void _presenter_MoveDoneEvent(Move move)
        {
            DoMove(move);
            uxBoard2D.InvalidateVisual();
        }

        void uxBoard3D_MoveDoneEvent(object sender, Board3D.Models.MoveDoneEventArgs e)
        {
            DoMove(e.Move);
            uxBoard3D.Redraw();
        }


        protected void StartNewGame(GameSettings settings)
        {
            _mng = GameManagerFactory.CreateGameManager(settings.GameType);
            if(settings.GameType == enumGameType.International)
                _mng.GameBoard.SetupStartPosition(4);
            else
                _mng.GameBoard.SetupStartPosition(3);

            SetGameManager(_mng);

            _iEngineLevel = settings.ComputerLevel;

            GameUpdate();

            if (settings.OnePlayerGame == true)
            {
                SwitchGameType(eGameType.OnePlayer);

                if (settings.ComputerPlaysWhite == true)
                {
                    _presenter.Rotated = true;
                    uxBoard2D.InvalidateVisual();
                    DoComputerMove();
                }
                else
                {
                    _presenter.Rotated = false;
                    uxBoard2D.InvalidateVisual();
                }
            }
            else
            {
                SwitchGameType(eGameType.TwoPlayer);
            }
        }

        protected void DoMove(Move move)
        {
            _presenter.GameManager.FinalizeMove(move);
            this.GameUpdate();
            uxBoard2D.InvalidateVisual();

            if (_mng.EvaluateGameResult() != enumGameResult.Unknown)
            {
                ShowGameResult(_mng.EvaluateGameResult());
                return;
            }

            if (_mng.GameType != enumGameType.Czech)
                return;

            if (_GameType == eGameType.TwoPlayer)
                return;

            if (_GameType == eGameType.OnePlayer)
            {
                uxBoard2D.Refresh();

                DoComputerMove();
            }
        }

        protected void DoComputerMove()
        {
            // convert board
            // create Game State Object for Engine
            _gameStateConfig = new MHWrap.GameStateConfig();
            _gameStateConfig.CheckersType = eCheckersType.CzechCheckers;
            _gameStateConfig.WhiteToMove = _mng.GameBoard.OnMove == enumFigureColor.White;
            _gameStateConfig.CheckersBoard = MHWrap.MoveHelper.ConvertCheckersBoard(_mng.GameBoard);
            _gameStateConfig.GameHistory = MHWrap.MoveHelper.ConvertMoveHistory(_mng);

            // convert models
            var checkersBoard = MHWrap.EngineMoveHelper.ConvertBoard(_gameStateConfig);
            var gameHistory = MHWrap.EngineMoveHelper.ConvertMoveHistory(_gameStateConfig);          

            _presenter.BlockInput();
            uxBoard3D.BlockUserInput();

            _engine.ComputeMove(eCheckersType.CzechCheckers, checkersBoard, _mng.GameBoard.OnMove == enumFigureColor.White,
                            _lstSettings[_iEngineLevel - 1], gameHistory);
        }

        protected void ComputerMoveDone(OutputBitBoard bb)
        {
            // convert the move from engine
            List<MHWrap.Position> move = MHWrap.EngineMoveHelper.Convert(bb, _gameStateConfig);

            // convert  model
            List<Position> posList = move.Select(i => new Position(i.Row, i.Col)).ToList();
            
            // do the move
            ComputerMove(posList);

            UpdateStatusBar(bb);

            _presenter.UnblockInput();
            uxBoard3D.UnblockUserInput();
        }

        protected void ComputerMove(List<Position> list)
        {
            if (list.Count < 2)
                throw new ApplicationException("ComputerMove: Position.Count < 2");

            Position startPos = list[0];
            Position lastPos = list[1];
            list.Remove(startPos);
            list.Remove(lastPos);

            Move move = _mng.CompleteMoveStep(startPos, lastPos);
            _mng.DoMoveStep(move);

            while (list.Count > 0)
            {
                Position finPos = list[0];
                Move curMove = _mng.CompleteMoveStep(lastPos, finPos);
                _mng.DoMoveStep(curMove);

                Move lastMove = move;
                while (lastMove.nextMove != null)
                    lastMove = lastMove.nextMove;
                lastMove.nextMove = curMove;

                lastPos = finPos;
                list.Remove(finPos);
            }

            _mng.FinalizeMove(move);
            _mng.MoveHistory.MoveBack();

            if (_bRunningComputerAdvice == true)
            {
                _mng.MoveHistory.ClearMovesToDo();
            }

            // animate move
            if (_eBoardType == eBoardType.e2D)
            {
                _presenter.AnimateMove(move);
            }
            else
            {
                uxBoard3D.AnimateMove(move);
            }
        }

        void _presenter_AnimationMoveFinishedEvent(object sender, EventArgs e)
        {
            if (_bRunningComputerAdvice == true)
            {
                _bRunningComputerAdvice = false;
                uxBoard2D.InvalidateVisual();
                uxBoard3D.Redraw();
                return;
            }

            _mng.MoveHistory.MoveForward();
            uxBoard2D.InvalidateVisual();
            uxBoard3D.Redraw();
            this.GameUpdate();

            // evaluate game result
            bool bStopMatch = false;
            if (_mng.EvaluateGameResult() != enumGameResult.Unknown)
            {
                ShowGameResult(_mng.EvaluateGameResult());
                bStopMatch = true;
            }


            // check engine match
            if (_GameType == eGameType.EngineMatch)
            {
                // if stop match
                if (bStopMatch == true)
                {
                    StopEngineMatch();
                    SwitchGameType(_savedGameType);
                    return;
                }

                // otherwise continue with another computer move
                DoComputerMove();
            }
        }

        protected void UpdateStatusBar(OutputBitBoard bb)
        {
#if USER
            uxDepthLabel.Content = string.Format(GetTextValue("APP_DepthInfo"), bb.Depth, bb.CalmPosDepth);
#else
            uxDepthLabel.Content = string.Format("Hloubka: [{0}/{1}], DTM: {2}", bb.Depth, bb.CalmPosDepth, bb.DTM);
#endif
            uxNumberOfNodes.Content = string.Format(GetTextValue("APP_NodeInfo"), FormatNumberOfNodes(bb.NumberOfNodes));
            uxNodesPerSec.Content = string.Format(GetTextValue("APP_NodesPerSec"), FormatNumberOfNodes(bb.NodesPerSecond));
        }

        private string FormatNumberOfNodes(int nodes)
        {
            if (nodes < 1024)
                return nodes.ToString();
            else if (nodes < 1024 * 1024)
            {
                return (nodes / 1024).ToString() + "K";
            }
            else
            {
                float nodesInM = Convert.ToSingle(nodes) / (1024 * 1024);
                return nodesInM.ToString("N1") + "M";
            }
        }

        protected void StartEngineMatch()
        {
            _presenter.BlockInput();
            uxBoard3D.BlockUserInput();

            DoComputerMove();
        }

        protected void StopEngineMatch()
        {
            _presenter.UnblockInput();
            uxBoard3D.UnblockUserInput();
        }

        //protected void WorkerMoveDone(object sender, ProgressChangedEventArgs e)
        //{
        //    OutputBitBoard bb = (OutputBitBoard)e.UserState;

        //    // convert to move to list of positions
        //    var posList = _converter.Convert(bb, _mng.GameBoard);

        //    UpdateStatusBar(bb);

        //    // do the move
        //    ComputerMove(posList);           
        //}

        protected void DoComputerAdvice()
        {
            _bRunningComputerAdvice = true;
            DoComputerMove();
        }
    }
}
